package com.seven.springboot.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 超时时间都用默认的，若有需求，可自行增加method
 * 
 * @author ligang
 *
 */
@SuppressWarnings("deprecation")
public class HttpClient4x {

	protected ObjectMapper objectMapper = new ObjectMapper();
	protected final Logger LOGGER = LoggerFactory.getLogger(getClass());

	public static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 30000;
	public static final int DEFAULT_CONNECT_TIMEOUT = 30000;
	public static final int DEFAULT_SO_TIMEOUT = 30000;
	public static final String DEFAULT_CHARSET = "UTF-8";

	public String doJsonSSLPost(String urlString, Map<String, Object> headers, Object postContents) throws Exception {

		String responseContent = null;
		CloseableHttpClient httpclient = createSSLClientDefault();

		RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
				.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).setSocketTimeout(DEFAULT_SO_TIMEOUT).build();

		HttpPost httppost = new HttpPost(urlString);
		httppost.setConfig(config);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httppost.addHeader(key, value.toString());
			}
		}

		String data = objectMapper.writeValueAsString(postContents);
		StringEntity se = new StringEntity(data, DEFAULT_CHARSET);
		se.setContentType("application/json;charset=" + DEFAULT_CHARSET);

		httppost.setEntity(se);
		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httppost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseContent = EntityUtils.toString(entity);
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}

				httpclient.close();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return responseContent;
	}

	/**
	 * 指定编码，指定超时时间
	 * 
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @param charSet
	 * @param timeOut
	 *            指定超时时间
	 * @return
	 * @throws Exception
	 */
	public String doJsonPost(String urlString, Map<String, Object> headers, Object postContents, String charSet,
			int timeOut) throws Exception {
		String responseContent = null;
		CloseableHttpClient httpclient = HttpClients.createDefault();
		RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(timeOut).setConnectTimeout(timeOut)
				.setSocketTimeout(timeOut).build();

		HttpPost httppost = new HttpPost(urlString);
		httppost.setConfig(config);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httppost.addHeader(key, value.toString());
			}
		}

		String data = objectMapper.writeValueAsString(postContents);
		LOGGER.debug("doJsonPost data: {}.", data);
		StringEntity se = new StringEntity(data, charSet);
		se.setContentType("application/json;charset=" + charSet);

		httppost.setEntity(se);
		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httppost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseContent = EntityUtils.toString(entity);
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}

				httpclient.close();
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			}
		}
		return responseContent;
	}

	/**
	 * JsonPost 使用默认编码， 默认超时时间
	 * 
	 * 
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @return
	 * @throws Exception
	 */
	public String doJsonPost(String urlString, Map<String, Object> headers, Object postContents) throws Exception {
		return doJsonPost(urlString, headers, postContents, DEFAULT_CHARSET, DEFAULT_SO_TIMEOUT);
	}

	/**
	 * JsonPost 指定编码
	 * 
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @param charSet
	 * @return
	 * @throws Exception
	 */
	public String doJsonPost(String urlString, Map<String, Object> headers, Object postContents, String charSet)
			throws Exception {
		return doJsonPost(urlString, headers, postContents, charSet, DEFAULT_SO_TIMEOUT);
	}

	/**
	 * JsonPost 指定超时时间
	 * 
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @param timeOut
	 * @return
	 * @throws Exception
	 */
	public String doJsonPost(String urlString, Map<String, Object> headers, Object postContents, int timeOut)
			throws Exception {
		return doJsonPost(urlString, headers, postContents, DEFAULT_CHARSET, timeOut);
	}

	/**
	 * 基本post, 默认编码
	 * 
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @return
	 * @throws Exception
	 */
	public String doPost(String urlString, Map<String, Object> headers, Map<String, Object> postContents)
			throws Exception {
		return doPost(urlString, headers, postContents, DEFAULT_CHARSET);
	}

	/**
	 * 基本post，指定编码
	 * 
	 * 
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @param charset
	 * @return
	 * @throws Exception
	 */
	public String doPost(String urlString, Map<String, Object> headers, Map<String, Object> postContents,
			String charset) throws Exception {
		String responseContent = null;
		CloseableHttpClient httpclient = HttpClients.createDefault();
		RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
				.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).setSocketTimeout(DEFAULT_SO_TIMEOUT).build();
		HttpPost httppost = new HttpPost(urlString);
		httppost.setConfig(config);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httppost.addHeader(key, value.toString());
			}
		}

		List<BasicNameValuePair> nvps = new ArrayList<BasicNameValuePair>();
		if (postContents != null) {
			for (String key : postContents.keySet()) {
				Object value = postContents.get(key);
				if (value != null) {
					nvps.add(new BasicNameValuePair(key, value.toString()));
				}
			}
		}

		httppost.setEntity(new UrlEncodedFormEntity(nvps, charset));

		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httppost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseContent = EntityUtils.toString(entity, charset);
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}

				httpclient.close();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return responseContent;
	}

	/**
	 * 基本post，指定编码、连接超时时长
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @param charset
	 * @param timeout
	 * @return
	 * @throws Exception
	 */
	public String doPost(String urlString, Map<String, Object> headers, Map<String, Object> postContents,
			String charset, int timeout) throws Exception {
		String responseContent = null;
		CloseableHttpClient httpclient = HttpClients.createDefault();
		RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(timeout)
				.setConnectTimeout(timeout).setSocketTimeout(timeout).build();
		HttpPost httppost = new HttpPost(urlString);
		httppost.setConfig(config);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httppost.addHeader(key, value.toString());
			}
		}

		List<BasicNameValuePair> nvps = new ArrayList<BasicNameValuePair>();
		if (postContents != null) {
			for (String key : postContents.keySet()) {
				Object value = postContents.get(key);
				if (value != null) {
					nvps.add(new BasicNameValuePair(key, value.toString()));
				}
			}
		}

		httppost.setEntity(new UrlEncodedFormEntity(nvps, charset));

		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httppost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseContent = EntityUtils.toString(entity, charset);
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}

				httpclient.close();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return responseContent;
	}
	
	/**
	 * 基本post, 默认编码
	 * 
	 * @param urlString
	 * @param headers
	 * @param postContents
	 * @return
	 * @throws Exception
	 */
	public String doPost(String urlString, Map<String, Object> headers, String postContents) throws Exception {
		return doPost(urlString, headers, postContents, DEFAULT_CHARSET);
	}

	public String doPost(String urlString, Map<String, Object> headers, String postContents, String charset)
			throws Exception {
		String responseContent = null;
		CloseableHttpClient httpclient = HttpClients.createDefault();
		RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
				.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).setSocketTimeout(DEFAULT_SO_TIMEOUT).build();
		HttpPost httppost = new HttpPost(urlString);
		httppost.setConfig(config);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httppost.addHeader(key, value.toString());
			}
		}

		StringEntity stringEntity = new StringEntity(postContents, charset);
		httppost.setEntity(stringEntity);
		stringEntity.setContentType("application/x-www-form-urlencoded; charset=" + DEFAULT_CHARSET);

		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httppost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseContent = EntityUtils.toString(entity, charset);
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}

				httpclient.close();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return responseContent;
	}

	/**
	 * 默认编码的doGet
	 * 
	 * @param urlString
	 * @param headers
	 * @return
	 * @throws Exception
	 */
	public String doGet(String urlString, Map<String, Object> headers) throws Exception {
		return doGet(urlString, headers, DEFAULT_CHARSET);
	}

	/**
	 * 指定编码的doGet
	 * 
	 * @param urlString
	 * @param headers
	 * @param charSet
	 * @return
	 * @throws Exception
	 */
	public String doGet(String urlString, Map<String, Object> headers, String charSet) throws Exception {
		String responseContent = null;
		CloseableHttpClient httpclient = HttpClients.createDefault();

		RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
				.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).setSocketTimeout(DEFAULT_SO_TIMEOUT).build();

		HttpGet httpget = new HttpGet(urlString);
		httpget.setConfig(config);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httpget.addHeader(key, value.toString());
			}
		}

		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseContent = EntityUtils.toString(entity, charSet);
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}

				httpclient.close();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return responseContent;
	}
	
	public String doSslGet(String urlString, Map<String, Object> headers, String charSet) throws Exception {
        String responseContent = null;
        CloseableHttpClient httpclient = createSSLClientDefault();

        RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
                .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).setSocketTimeout(DEFAULT_SO_TIMEOUT).build();

        HttpGet httpget = new HttpGet(urlString);
        httpget.setConfig(config);

        if (headers != null) {
            for (String key : headers.keySet()) {
                Object value = headers.get(key);
                httpget.addHeader(key, value.toString());
            }
        }

        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpget);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                responseContent = EntityUtils.toString(entity, charSet);
            }
        } finally {
            try {
                if (response != null) {
                    response.close();
                }

                httpclient.close();
            } catch (Exception e) {
                LOGGER.error("", e);
            }
        }
        return responseContent;
    }

	/**
	 * 使用http get方式下载文件
	 * 
	 * @param url
	 * @param headers
	 * @return	文件InputStream流，下载不成功返回null
	 * @throws UnsupportedOperationException
	 * @throws IOException
	 */
	public InputStream downloadFile(String url, Map<String, Object> headers) throws UnsupportedOperationException, IOException {

		CloseableHttpClient httpclient = HttpClients.createDefault();
		RequestConfig config = RequestConfig.custom()
				// .setConnectionRequestTimeout(-1)
				// .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT)
				// .setSocketTimeout(DEFAULT_SO_TIMEOUT)
				.build();

		HttpGet httpGet = new HttpGet(url);
		httpGet.setConfig(config);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httpGet.addHeader(key, value.toString());
			}
		}
		CloseableHttpResponse httpResponse = httpclient.execute(httpGet);
		HttpEntity entity = httpResponse.getEntity();

//		long length = entity.getContentLength();
//		if (length <= 0) {
//			LOGGER.warn("download file not exists for url: {}", url);
//			return null;
//		}
		
		InputStream in = entity.getContent();
		return in;
	}

	public String postFile(String url, String fileName, Map<String, Object> params, Map<String, Object> headers)
			throws Exception {

		CloseableHttpClient httpclient = HttpClients.createDefault();
		// 请求处理页面
		HttpPost httppost = new HttpPost(url);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httppost.addHeader(key, value.toString());
			}
		}
		// 创建待处理的文件
		FileBody file = new FileBody(new File(fileName));

		// 对请求的表单域进行填充
		MultipartEntity reqEntity = new MultipartEntity();
		reqEntity.addPart("up_file", file);

		if (params != null) {
			for (String key : params.keySet()) {
				String value = params.get(key).toString();
				// 创建待处理的表单域内容文本
				StringBody bodyValue = new StringBody(value);
				reqEntity.addPart(key, bodyValue);
			}
		}

		// 设置请求
		httppost.setEntity(reqEntity);
		CloseableHttpResponse response = null;
		try {
			// 执行
			response = httpclient.execute(httppost);

			HttpEntity entity = response.getEntity();
			if (entity != null) {
				String responseContent = EntityUtils.toString(entity);
				return responseContent;
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}

				httpclient.close();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}

		return null;
	}

	public CloseableHttpClient createSSLClientDefault() {

		try {
			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
				// 信任所有
				public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
					return true;
				}
			}).build();

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
					SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
			return HttpClients.custom().setSSLSocketFactory(sslsf).build();

		} catch (Exception e) {
			LOGGER.error("", e);
		}
		return HttpClients.createDefault();

	}
	
	public String getGetCookie(String urlString, Map<String, Object> headers) throws Exception {
		RequestConfig config = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
				.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).setSocketTimeout(DEFAULT_SO_TIMEOUT).build();
		// 创建cookie store的本地实例
	    CookieStore cookieStore = new BasicCookieStore();
	    // 创建HttpClient上下文
	    HttpClientContext context = HttpClientContext.create();
	    context.setCookieStore(cookieStore);
	    CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(config).setDefaultCookieStore(cookieStore).build();
		
	    HttpGet httpget = new HttpGet(urlString);

		if (headers != null) {
			for (String key : headers.keySet()) {
				Object value = headers.get(key);
				httpget.addHeader(key, value.toString());
			}
		}
		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httpget,context);
			if(!ListUtils.isEmpty(cookieStore.getCookies()) && cookieStore.getCookies().get(0) != null) {
				Cookie cookie = cookieStore.getCookies().get(0);
				return cookie.getName() + "=" + cookie.getValue();
			}
		} finally {
			try {
				if (response != null) {
					response.close();
				}
				httpclient.close();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return null;
	}
}
